package com.ffcs.cn.action.base.treeTable;

import com.ffcs.cn.DevelopProperties;
import com.supermap.desktop.controls.ui.UICommonToolkit;
import com.supermap.desktop.controls.ui.controls.SmDialog;
import com.supermap.desktop.controls.ui.controls.SmTextFieldSearch;
import com.supermap.desktop.core.ui.controls.GridBagConstraintsHelper;
import com.supermap.desktop.core.utilties.DefaultValues;
import com.supermap.desktop.core.utilties.StringUtilities;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;
import org.jdesktop.swingx.treetable.MutableTreeTableNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.userdefine.ui.openapi.util.TextRange;
import org.jetbrains.userdefine.ui.speedSearch.SpeedSearchComparator;
import org.jetbrains.userdefine.ui.speedSearch.TreeSpeedSearch;
import org.jetbrains.userdefine.ui.util.containers.Convertor;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.*;
import java.text.MessageFormat;


public class DialogJTreeTable extends SmDialog {

	private JToolBar toolBarOperator;
	private JCheckBox checkBoxShowCheck;// 切换渲染器，默认不选中时，使用 demoJTreeTableTreeCellRender，选中时使用 demoJTreeTableTreeCellRenderCheck
	private JCheckBox checkBoxShowLastImage;// 决定树节点列是否显示文本后面的图标，不选中则不显示
	private SmTextFieldSearch textFieldSearch;// 搜索控件
	private TreeTableNode rootNode = new TreeTableNode(new TreeTableData(""));// 树根节点，所有数据节点都在根节点之下
	private DefaultTreeTableModelDemo defaultTreeTableModelDemo;// 树表格model
	private JXTreeTable jxTreeTableDemo;
	private JScrollPane scrollPane;
	private DemoJTreeTableTreeCellRenderCheck demoJTreeTableTreeCellRenderCheck = new DemoJTreeTableTreeCellRenderCheck();
	private DemoJTreeTableTreeCellRender demoJTreeTableTreeCellRender = new DemoJTreeTableTreeCellRender();

	public static final int COLUMN_INDEX_NAME = 0;
	public static final int COLUMN_INDEX_DELETE = 1;
	public static final int COLUMN_INDEX_ADD = 2;
	public static final int COLUMN_INDEX_TIME = 3;

	public DialogJTreeTable() {
		initComponents();
		initComponentsStatus();
		initLayout();
		initResources();
		registerEvents();
		this.setSize(new Dimension(500, 631));
	}

	private void initComponents() {
		this.toolBarOperator = new JToolBar();
		this.checkBoxShowCheck = new JCheckBox();
		this.checkBoxShowLastImage = new JCheckBox();
		this.textFieldSearch = new SmTextFieldSearch();

		this.defaultTreeTableModelDemo = new DefaultTreeTableModelDemo(this.rootNode);// 根据树根节点构造树Model
		this.jxTreeTableDemo = new JXTreeTable(this.defaultTreeTableModelDemo);
		this.scrollPane = new JScrollPane(this.jxTreeTableDemo);
	}

	private void initComponentsStatus() {
		this.toolBarOperator.add(this.checkBoxShowCheck);
		this.toolBarOperator.addSeparator(new Dimension(DefaultValues.getSystemFontZoomValue(20), DefaultValues.getDefaultComponentHeight()));
		this.toolBarOperator.add(this.checkBoxShowLastImage);
		this.toolBarOperator.setFloatable(false);
		// 根节点不需要显示，隐藏掉
		this.jxTreeTableDemo.setRootVisible(false);
		this.jxTreeTableDemo.setShowsRootHandles(true);
		// 设置TreeTableNode类型的渲染器，即后面三列的渲染器
		this.jxTreeTableDemo.setDefaultRenderer(TreeTableNode.class, new DemoJTreeTableTableCellRender());
		// 设置树节点列的渲染器
		this.jxTreeTableDemo.setTreeCellRenderer(this.demoJTreeTableTreeCellRender);
		setTimeColumnCellEditor();
		// 添加数据，注意添加数据通过model.insertNodeInto方法，不要直接add,否则add后还需要刷新整个树，比较麻烦
		for (int i = 0; i < 10; i++) {
			TreeTableData treeTableDataI = new TreeTableData(i + "");
			TreeTableNode treeTableNodeI = new TreeTableNode(treeTableDataI);
			this.defaultTreeTableModelDemo.insertNodeInto(treeTableNodeI, this.rootNode, this.rootNode.getChildCount());

			for (int j = 1; j < 10; j++) {
				TreeTableData treeTableDataJ = new TreeTableData(i * 10 + j + "");
				TreeTableNode treeTableNodeJ = new TreeTableNode(treeTableDataJ);
				this.defaultTreeTableModelDemo.insertNodeInto(treeTableNodeJ, treeTableNodeI, treeTableNodeI.getChildCount());
				for (int k = 1; k < 4; k++) {
					TreeTableData treeTableDataK = new TreeTableData(i * 10 + j * 10 + k + "");
					TreeTableNode treeTableNodeK = new TreeTableNode(treeTableDataK);
					this.defaultTreeTableModelDemo.insertNodeInto(treeTableNodeK, treeTableNodeJ, treeTableNodeJ.getChildCount());
				}
			}
		}
		applySpeedSearch();
	}

	// 树表格支持搜索
	private void applySpeedSearch() {
		JTree jTree = (JTree) jxTreeTableDemo.getCellRenderer(0, jxTreeTableDemo.getHierarchicalColumn());
		Convertor<? super TreePath, String> stringConvertor = (Convertor<TreePath, String>) o -> {
			// TreePath拿到树节点，进而拿到要搜索的数据返回给快速搜索器
			TreeTableNode treeTableNode = (TreeTableNode) o.getLastPathComponent();
			return treeTableNode.getTreeTableData().getValue();
		};
		// 构造快速搜索器，必须实现matchingFragments方法，matchingFragments内部做了：当搜索文本框不为空时，进行匹配
		TreeSpeedSearch treeSpeedSearch = new TreeSpeedSearch(jTree, stringConvertor) {
			@Override
			public Iterable<TextRange> matchingFragments(@NotNull String text) {
				if (!StringUtilities.isNullOrEmpty(textFieldSearch.getText())) {
					SpeedSearchComparator comparator = getComparator();
					return comparator.matchingFragments(textFieldSearch.getText(), text);
				}
				return super.matchingFragments(text);
			}
		};
		this.demoJTreeTableTreeCellRender.setTreeSpeedSearch(treeSpeedSearch);
		this.demoJTreeTableTreeCellRenderCheck.setTreeSpeedSearch(treeSpeedSearch);
	}

	private void setTimeColumnCellEditor() {
		// 设置第四列的编辑器，注意：在树结构发生改变后，需要重新设置，因为树结构改变时会将之前设置的编辑器覆盖掉
		this.jxTreeTableDemo.getColumnModel().getColumn(COLUMN_INDEX_TIME).setCellEditor(new DefaultCellEditor(new JComboBox()) {
			private Component component;

			private ActionListener actionListener = new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					stopCellEditing();
					if (component instanceof JComboBox) {
						((JComboBox) component).removeActionListener(this);

					}
				}
			};

			@Override
			public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
				if (value instanceof TreeTableNode) {
					TreeTableNode treeTableNode = (TreeTableNode) value;
					component = treeTableNode.getRenderComponent(COLUMN_INDEX_TIME);

					if (component instanceof JComboBox) {
						((JComboBox) component).setSelectedItem((treeTableNode.getTreeTableData().getTime()));
						((JComboBox) component).addActionListener(actionListener);
					}
					return component;
				}
				return null;
			}

			@Override
			public Object getCellEditorValue() {
				if (component instanceof JComboBox) {
					return ((JComboBox) component).getSelectedItem();
				}
				return "";
			}
		});
	}

	private void initLayout() {
		this.setLayout(new GridBagLayout());

		this.getContentPane().add(this.toolBarOperator, new GridBagConstraintsHelper(0, 0, 1, 1).setInsets(GridBagConstraintsHelper.FRAME_CONTROL_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP, 0, GridBagConstraintsHelper.FRAME_CONTROL_GAP).setFill(GridBagConstraints.HORIZONTAL));
		this.getContentPane().add(this.textFieldSearch, new GridBagConstraintsHelper(0, 1, 1, 1).setInsets(GridBagConstraintsHelper.CONTROLS_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP, 0, GridBagConstraintsHelper.FRAME_CONTROL_GAP).setFill(GridBagConstraints.HORIZONTAL));
		this.getContentPane().add(this.scrollPane, new GridBagConstraintsHelper(0, 2, 1, 1).setInsets(GridBagConstraintsHelper.CONTROLS_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP).setFill(GridBagConstraints.BOTH).setWeight(1, 1));
	}

	private void initResources() {
		this.setTitle(DevelopProperties.getString("String_JTreeTable"));
		this.checkBoxShowCheck.setText(DevelopProperties.getString("String_SwitchRender"));
		this.checkBoxShowLastImage.setText(DevelopProperties.getString("String_ShowOperatorImage"));
	}

	private void registerEvents() {
		this.checkBoxShowCheck.addActionListener(this.actionListenerSwitchRender);
		this.checkBoxShowLastImage.addActionListener(this.actionListenerShowOperatorImage);
		this.jxTreeTableDemo.addMouseListener(this.mouseListener);
		this.textFieldSearch.getDocument().addDocumentListener(this.documentListener);
	}

	private ActionListener actionListenerSwitchRender = new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
			if (checkBoxShowCheck.isSelected()) {
				// 当选中切换渲染checkbox时，就使用demoJTreeTableTreeCellRenderCheck渲染器，且不显示最后的图标
				demoJTreeTableTreeCellRenderCheck.setShowOperatorIcon(false);
				jxTreeTableDemo.setTreeCellRenderer(demoJTreeTableTreeCellRenderCheck);
			} else {
				// 当未选中切换渲染checkbox时，就使用demoJTreeTableTreeCellRender渲染器
				jxTreeTableDemo.setTreeCellRenderer(demoJTreeTableTreeCellRender);
				checkBoxShowLastImage.setSelected(false);
			}
			// 切换渲染器后需要刷新
			jxTreeTableDemo.repaint();
		}
	};

	private ActionListener actionListenerShowOperatorImage = new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
			// 可以参考actionListenerSwitchRender，作用差不多
			if (checkBoxShowLastImage.isSelected()) {
				demoJTreeTableTreeCellRenderCheck.setShowOperatorIcon(true);
				jxTreeTableDemo.setTreeCellRenderer(demoJTreeTableTreeCellRenderCheck);
			} else {
				if (checkBoxShowCheck.isSelected()) {
					demoJTreeTableTreeCellRenderCheck.setShowOperatorIcon(false);
					jxTreeTableDemo.setTreeCellRenderer(demoJTreeTableTreeCellRenderCheck);
				} else {
					jxTreeTableDemo.setTreeCellRenderer(demoJTreeTableTreeCellRender);
					checkBoxShowLastImage.setSelected(false);
				}
			}
			jxTreeTableDemo.repaint();
		}
	};

	private MouseListener mouseListener = new MouseAdapter() {
		@Override
		public void mouseClicked(MouseEvent e) {
			if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
				// 响应鼠标左键单机事件，
				int x = e.getX();
				int y = e.getY();
				// 根据鼠标位置拿到树节点
				TreePath pathForLocation = jxTreeTableDemo.getPathForLocation(x, y);
				if (pathForLocation != null) {
					TreeTableNode treeTableNode = (TreeTableNode) pathForLocation.getLastPathComponent();
					if (checkBoxShowCheck.isSelected() || checkBoxShowLastImage.isSelected()) {
						JTree jTree = (JTree) jxTreeTableDemo.getCellRenderer(0, jxTreeTableDemo.getHierarchicalColumn());
						// 树节点随着子节点层级越深，前面空白区域越多，所以需要拿到的鼠标x坐标减去前面空白区域，进而可以匹配鼠标点击的区域是checkbox还是最后一个图标
						int offset = x - jTree.getUI().getPathBounds(jTree, pathForLocation).x;
						// treeTableNode.getRenderComponent(0) 每次拿到的都是最新的，所以得确保跟渲染的一样，该显示的显示，该隐藏的隐藏
						PanelCheck panelCheck = (PanelCheck) treeTableNode.getRenderComponent(0);
						panelCheck.setLabelImageVisible(checkBoxShowLastImage.isSelected());
						if (panelCheck.hitCheckBox(offset)) {
							// 如果点击的是复选框，则同步选中或不选中此节点下的所有子节点
							setSelected(treeTableNode, !treeTableNode.getTreeTableData().isSelected());
							jxTreeTableDemo.repaint();
							return;
						} else if (panelCheck.hitLastImage(offset)) {
							// 如果点击的是最后一个图标，则弹提示框显示值
							UICommonToolkit.showMessageDialog(MessageFormat.format(DevelopProperties.getString("String_CurrentClickedLineData"), treeTableNode.getTreeTableData().getValue()));
							return;
						}
					}
					// 获取鼠标点击的那一列
					int column = jxTreeTableDemo.columnAtPoint(e.getPoint());

					if (column == COLUMN_INDEX_DELETE) {
						// 如果是删除列，如果处于搜索状态，先清除搜索内容，再删除节点，注：删除节点用removeNodeFromParent方法，不要直接remove，要不然得刷新树
						if (!StringUtilities.isNullOrEmpty(textFieldSearch.getText())) {
							clearSearchText();
						}
						// 先清除选中的行
						jxTreeTableDemo.clearSelection();
						// 获取鼠标点击的行
						int row = jxTreeTableDemo.getRowForPath(pathForLocation);
						// 删除行
						defaultTreeTableModelDemo.removeNodeFromParent(treeTableNode);
						// 删除行后选中行，方便操作
						if (jxTreeTableDemo.getRowCount() > row) {
							jxTreeTableDemo.setRowSelectionInterval(row, row);
						} else if (jxTreeTableDemo.getRowCount() > 0) {
							int selectedRow = row - 1;
							if (selectedRow < 0) {
								selectedRow = 0;
							}
							jxTreeTableDemo.setRowSelectionInterval(selectedRow, selectedRow);
						}


					} else if (column == COLUMN_INDEX_ADD) {
						// 如果是添加列，如果处于搜索状态，先清除搜索内容，再添加节点，将当前选中的节点数据拷贝添加到当前节点下面
						if (!StringUtilities.isNullOrEmpty(textFieldSearch.getText())) {
							clearSearchText();
						}
						TreeTableData treeTableData = new TreeTableData(treeTableNode.getTreeTableData().getValue());
						TreeTableNode treeTableNodeNew = new TreeTableNode(treeTableData);
						defaultTreeTableModelDemo.insertNodeInto(treeTableNodeNew, (MutableTreeTableNode) treeTableNode.getParent(), treeTableNode.getParent().getIndex(treeTableNode) + 1);
					}
				}
			}
		}
	};

	private DocumentListener documentListener = new DocumentListener() {
		@Override
		public void insertUpdate(DocumentEvent e) {
			search();
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			search();
		}

		@Override
		public void changedUpdate(DocumentEvent e) {
			search();
		}
	};

	private void setSelected(TreeTableNode treeTableNode, boolean selected) {
		treeTableNode.getTreeTableData().setSelected(selected);
		int childCount = treeTableNode.getChildCount();
		if (childCount > 0) {
			for (int i = 0; i < childCount; i++) {
				setSelected(treeTableNode.getChildAt(i), selected);
			}
		}
	}

	private void search() {
		if (textFieldSearch == null) {
			return;
		}
		// 将文本框输入搜索文本传给TreeTableNode，并刷新节点进行搜索
		TreeTableNode.search(textFieldSearch.getText());
		this.rootNode.refreshNodeState();
		// 搜索完之后，需要发送fireTreeStructureChanged，让树刷新，并展开所有节点
		this.defaultTreeTableModelDemo.firePathChanged(this.rootNode);
		if (!StringUtilities.isNullOrEmpty(this.textFieldSearch.getText())) {
			this.jxTreeTableDemo.expandAll();
		}
	}

	private void clearSearchText() {
		textFieldSearch.setText("");
		search();
	}

	private class DefaultTreeTableModelDemo extends DefaultTreeTableModel {

		// 树表格列名
		private final String[] columnNames = new String[]{
				DevelopProperties.getString("String_Name"),
				DevelopProperties.getString("String_Delete"),
				DevelopProperties.getString("String_Add"),
				DevelopProperties.getString("String_Time"),

		};

		public DefaultTreeTableModelDemo(DefaultMutableTreeTableNode defaultMutableTreeTableNode) {
			super(defaultMutableTreeTableNode);
		}

		@Override
		public int getColumnCount() {
			return columnNames.length;
		}

		@Override
		public String getColumnName(int column) {
			return columnNames[column];
		}

		@Override
		public Class<?> getColumnClass(int columnIndex) {
			// 返回列class,注意要跟渲染器、TreeTableNode.getValueAt匹配
			return TreeTableNode.class;
		}

		public void firePathChanged(TreeTableNode treeTableNode) {
			// 刷新指定节点
			modelSupport.fireTreeStructureChanged(new TreePath(getPathToRoot(treeTableNode)));
			// 刷新节点会重置编辑器，重新设置编辑器
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					setTimeColumnCellEditor();
				}
			});
		}
	}
}
